package cn.bonoon.handler.impl;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import cn.bonoon.core.plugins.LoginService;
import cn.bonoon.entities.AccountEntity;
import cn.bonoon.entities.RoleEntity;
import cn.bonoon.handler.LoginUserDetailsService;
import cn.bonoon.handler.OnLoginFilter;
import cn.bonoon.kernel.FlagType;
import cn.bonoon.kernel.exceptions.DataBaseExcetion;
import cn.bonoon.kernel.security.LogonUser;
import cn.bonoon.kernel.security.ProxyLogonUser;
import cn.bonoon.kernel.security.StandardLogonUser;
import cn.bonoon.kernel.util.StringHelper;

public class UserDetailsHandlerImpl implements LoginUserDetailsService {

	protected final Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private LoginService loginService;
	
	/** 是否开启强制修改密码的要求，默认为true */
	private boolean forcedChangePasswordEnable = true;

//	@Value("${user.login.count}")
//	private int tryCount;
//
//	@Value("${user.login.lock.time}")
//	private int lockTime;
	@Autowired(required = false)
	private List<OnLoginFilter> filters;

	public void setFilters(List<OnLoginFilter> filters) {
		this.filters = filters;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		AccountEntity account = internalUser(username);

//		Integer tc = account.getTryLoginCount();
//		if(null != tc && tc >= tryCount){
//			Date clAt = account.getCurrentLogonAt();
//			Calendar cal = Calendar.getInstance();
//			cal.setTime(clAt);
//			cal.add(Calendar.SECOND, lockTime);
//			Date time = cal.getTime();
//			if(time.after(new Date())){
//				throw new UsernameNotFoundException("登录错误超过3次，请在5分钟后再登录！");
//			}
//		}

		__checkedFilters(account);
		
		LogonUser user = buildLogonUser(account, loginService, forcedChangePasswordEnable);
		Boolean proxyable = account.getProxyable();
		if(user.isSuper() || (null != proxyable && proxyable)){
			//目前只有超级管理员才能代理处理
			log.info("可以代管其他账号：{}", username);
			return new ProxyLogonUser(user);
		}
		return user;
	}

	private AccountEntity internalUser(String username) throws UsernameNotFoundException{
		AccountEntity account = null;
		try{
			account = loginService.loadByLoginName(username);
		}catch (Exception e){
			log.info("数据库连接超时");
			throw new DataBaseExcetion("连接超时");
		}

		if (null == account || !account.getLoginName().equals(username)) {
			log.info("找不到用户：{}", username);
			throw new UsernameNotFoundException(username + " 找不到该用户！");
		}

		return account;
	}

	private void __checkedFilters(AccountEntity account) {
		if(null != filters){
			for(OnLoginFilter filter : filters){
				filter.filter(account);
			}
		}
	}

	@Override
	public LogonUser loadUser(String username) throws UsernameNotFoundException {
		AccountEntity account = internalUser(username);

		try{
			__checkedFilters(account);
		}catch (Exception e) {
			return buildLogonUser(account, loginService, forcedChangePasswordEnable, e.getMessage(), true);
			//message = e.getMessage();
		}
		return buildLogonUser(account, loginService, forcedChangePasswordEnable);
	}

	public void setForcedChangePasswordEnable(boolean forcedChangePasswordEnable) {
		this.forcedChangePasswordEnable = forcedChangePasswordEnable;
	}
	
	public static LogonUser buildLogonUser(
			AccountEntity user, 
			LoginService loginService, 
			boolean forcedChangePasswordEnable,
			String message, boolean warning) {
		 List<RoleEntity> roles = loginService.getAccountRoles(user);
		 List<GrantedAuthority> gAuthorities = parseAuthority(user, roles);
		 StandardLogonUser slUser = new StandardLogonUser(user, gAuthorities, forcedChangePasswordEnable);
		 slUser.title(message);
		 slUser.warning(warning);
		 loginService.policy().policy(slUser, RoleEntity.class, roles);
		 return slUser;
	}
	
	public static LogonUser buildLogonUser(
			AccountEntity user, 
			LoginService loginService, 
			boolean forcedChangePasswordEnable){
		return buildLogonUser(user, loginService, forcedChangePasswordEnable, null, false);
	}
	
	protected static List<GrantedAuthority> parseAuthority(AccountEntity user, List<RoleEntity> roles){
		
		/* 用来控制当前用户可以访问哪些路径； TODO 这个需要重视，以后尽量使用。 */
		List<GrantedAuthority> authorities = new ArrayList<>();
		List<String> tmpRoles = new ArrayList<>();
		
		for (RoleEntity role : roles) {
			StringHelper.toList(tmpRoles, role.getRoleKey());
		}
		
		if (user.getFlag() == FlagType.SUPER){
			// 超级管理员
			authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
		}
		
		for (String r : tmpRoles) {
			authorities.add(new SimpleGrantedAuthority(r));
		}
		
		return authorities;
	}
}
